home *** CD-ROM | disk | FTP | other *** search
Wrap
////////// // // File: SpriteUtilities.c // // Contains: Utilities for adding sprite tracks to QuickTime movies. // // Written by: Sean Allen // Revised by: Chris Flick and Tim Monroe // // Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved. // // Change History (most recent first): // // <3> 03/27/98 rtm added error checking to AddPICTImageToKeyFrameSample to prevent crashes // if PICT resources not found // <2> 03/27/98 cf further fixes for Windows compiles // <1> 03/26/98 rtm made fixes for Windows compiles // // ////////// #ifndef _SPRITEUTILITIES_ #include "SpriteUtilities.h" #endif #ifndef _IMAGECOMPRESSIONUTILITIES_ #include "ImageCompressionUtilities.h" #endif #ifndef __ENDIANUTILITIES__ #include "EndianUtilities.h" #endif #ifndef __RESOURCES__ #include <Resources.h> #endif #ifndef __QUICKTIMECOMPONENTS__ #include <QuickTimeComponents.h> #endif #ifndef __MEDIAHANDLERS__ #include <MediaHandlers.h> #endif // exception handling macros #define FailIf(a, e) {if (a) { err = e; goto bail; }} #define FailOSErr(a) {if (err = a) goto bail;} #define FailMemErr(a) {a; if (err = MemError()) goto bail;} OSErr GetImageDescription( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, ImageDescriptionHandle imageDesc ); OSErr SetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long groupID ); OSErr GetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long *groupID ); OSErr SetSpriteData( QTAtomContainer sprite, Point *location, short *visible, short *layer, short *imageIndex, ModifierTrackGraphicsModeRecord *graphicsMode, StringPtr spriteName, QTAtomContainer actionAtoms ) { OSErr err = noErr; QTAtom propertyAtom; if ( location ) { MatrixRecord matrix; SetIdentityMatrix( &matrix ); matrix.matrix[2][0] = ((long)location->h << 16); matrix.matrix[2][1] = ((long)location->v << 16); EndianUtils_MatrixRecord_NtoB( &matrix ); if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyMatrix, 1, nil )) == 0 ) FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyMatrix, 1, 0, sizeof(MatrixRecord), &matrix, nil ) ) else FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(MatrixRecord), &matrix ) ); } if ( visible ) { short tempVisible = *visible; tempVisible = EndianS16_NtoB(tempVisible); if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyVisible, 1, nil )) == 0 ) FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyVisible, 1, 0, sizeof(short), &tempVisible, nil ) ) else FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), &tempVisible ) ); } if ( layer ) { short tempLayer = *layer; tempLayer = EndianS16_NtoB(tempLayer); if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyLayer, 1, nil )) == 0 ) FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyLayer, 1, 0, sizeof(short), &tempLayer, nil ) ) else FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), &tempLayer ) ); } if ( imageIndex ) { short tempImageIndex = *imageIndex; tempImageIndex = EndianS16_NtoB(tempImageIndex); if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyImageIndex, 1, nil )) == 0 ) FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyImageIndex, 1, 0, sizeof(short), &tempImageIndex, nil ) ) else FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(short), &tempImageIndex ) ); } if ( graphicsMode ) { ModifierTrackGraphicsModeRecord tempGraphicsMode; tempGraphicsMode.graphicsMode = EndianU32_NtoB(graphicsMode->graphicsMode); tempGraphicsMode.opColor.red = EndianU16_NtoB(graphicsMode->opColor.red); tempGraphicsMode.opColor.green = EndianU16_NtoB(graphicsMode->opColor.green); tempGraphicsMode.opColor.blue = EndianU16_NtoB(graphicsMode->opColor.blue); if ( (propertyAtom = QTFindChildByIndex( sprite, 0, kSpritePropertyGraphicsMode, 1, nil )) == 0 ) FailOSErr( QTInsertChild( sprite, 0, kSpritePropertyGraphicsMode, 1, 0, sizeof(tempGraphicsMode), &tempGraphicsMode, nil ) ) else FailOSErr( QTSetAtomData( sprite, propertyAtom, sizeof(tempGraphicsMode), &tempGraphicsMode ) ); } if( spriteName ) { QTAtom spriteNameAtom; if ( (spriteNameAtom = QTFindChildByIndex( sprite, 0, kSpriteNameAtomType, 1, nil )) == 0 ) FailOSErr( QTInsertChild( sprite, 0, kSpriteNameAtomType, 1, 0, spriteName[0]+1, spriteName, nil ) ) else FailOSErr( QTSetAtomData( sprite, spriteNameAtom, spriteName[0]+1, spriteName ) ); } if ( actionAtoms ) { FailOSErr( QTInsertChildren( sprite, kParentAtomIsContainer, actionAtoms ) ); } bail: if ( err && sprite ) QTRemoveChildren( sprite, 0 ); return err; } OSErr AddSpriteToSample( QTAtomContainer theSample, QTAtomContainer theSprite, QTAtomID spriteID ) { OSErr err = noErr; QTAtom newSpriteAtom; FailIf ( QTFindChildByID( theSample, 0, kSpriteAtomType, spriteID, nil ), paramErr ); FailOSErr( QTInsertChild( theSample, 0, kSpriteAtomType, spriteID, 0, 0, nil, &newSpriteAtom ) ); // index of zero means append FailOSErr( QTInsertChildren( theSample, newSpriteAtom, theSprite ) ); bail: return err; } OSErr AddSpriteSampleToMedia( Media theMedia, QTAtomContainer sample, TimeValue duration, Boolean isKeyFrame, TimeValue *sampleTime ) { OSErr err = noErr; SampleDescriptionHandle sampleDesc = nil; FailMemErr( sampleDesc = (SampleDescriptionHandle) NewHandleClear( sizeof(SpriteDescription ) ) ); FailOSErr( AddMediaSample( theMedia, (Handle) sample, 0, GetHandleSize( sample ), duration, sampleDesc, 1, (short)(isKeyFrame ? 0 : mediaSampleNotSync), sampleTime ) ); bail: if ( sampleDesc ) DisposeHandle( (Handle) sampleDesc ); return err; } OSErr AddCompressedSpriteSampleToMedia( Media theMedia, QTAtomContainer sample, TimeValue duration, Boolean isKeyFrame, OSType dataCompressorType, TimeValue *sampleTime ) { OSErr err = noErr; SpriteDescriptionHandle sampleDesc = nil; Handle compressedSample = nil; ComponentInstance dataCompressorComponentInstance = nil; err = OpenADefaultComponent(DataCompressorComponentType, dataCompressorType, &dataCompressorComponentInstance); if( err ) goto bail; FailMemErr( sampleDesc = (SpriteDescriptionHandle) NewHandleClear( sizeof(SpriteDescription) ) ); if( dataCompressorComponentInstance != nil ) { UInt32 compressBufferSize, actualCompressedSize, decompressSlop = 0; UInt32 uncompressedSize; SignedByte saveState = HGetState( sample ); err = (OSErr)DataCodecGetCompressBufferSize( dataCompressorComponentInstance, GetHandleSize( sample ), &compressBufferSize ); if(err) goto bail; compressedSample = NewHandle( sizeof(UInt32) + compressBufferSize ); err = MemError(); if(err) goto bail; HLockHi( sample ); HLockHi( compressedSample ); err = (OSErr)DataCodecCompress( dataCompressorComponentInstance, *sample, GetHandleSize(sample), *compressedSample + sizeof(UInt32), // room for size at beginning compressBufferSize, &actualCompressedSize, &decompressSlop ); HSetState( sample, saveState ); HUnlock( compressedSample ); if(err) goto bail; SetHandleSize( compressedSample, sizeof(UInt32) + actualCompressedSize ); err = MemError(); if(err) goto bail; (**sampleDesc).decompressorType = EndianU32_NtoB(dataCompressorType); uncompressedSize = GetHandleSize(sample); (*(UInt32*) *compressedSample) = EndianU32_NtoB(uncompressedSize); // add uncompressed size at beginning FailOSErr( AddMediaSample( theMedia, (Handle) compressedSample, 0, GetHandleSize( compressedSample ), duration, (SampleDescriptionHandle) sampleDesc, 1, (short)(isKeyFrame ? 0 : mediaSampleNotSync), sampleTime ) ); } else { FailOSErr( AddMediaSample( theMedia, (Handle) sample, 0, GetHandleSize( sample ), duration, (SampleDescriptionHandle) sampleDesc, 1, (short)(isKeyFrame ? 0 : mediaSampleNotSync), sampleTime ) ); } bail: if ( compressedSample ) DisposeHandle( compressedSample ); if ( sampleDesc ) DisposeHandle( (Handle) sampleDesc ); if ( dataCompressorComponentInstance ) CloseComponent( dataCompressorComponentInstance ); return err; } OSErr AddPICTImageToKeyFrameSample( QTAtomContainer keySample, short pictID, RGBColor *keyColor, QTAtomID id, FixedPoint *registrationPoint, StringPtr imageName ) { OSErr err = noErr; PicHandle picture; Handle compressedPicture = NULL; ImageDescriptionHandle idh = NULL; // get picture from resource picture = (PicHandle) GetPicture( pictID ); if (picture == NULL) err = resNotFound; if(err) goto bail; DetachResource( (Handle)picture ); // convert it to image data compressed by the animation compressor err = RecompressPictureWithTransparency( picture, keyColor, nil, &idh, &compressedPicture ); if(err) goto bail; // add it to the keySample HLock( compressedPicture ); err = AddCompressedImageToKeyFrameSample( keySample, idh, GetHandleSize( compressedPicture ), *compressedPicture, id, registrationPoint, imageName ); bail: if ( picture ) KillPicture( picture ); if ( compressedPicture ) DisposeHandle( compressedPicture ); if ( idh ) DisposeHandle( (Handle)idh ); return err; } OSErr AddCompressedImageToKeyFrameSample( QTAtomContainer keySample, ImageDescriptionHandle idh, long dataSize, Ptr compressedDataPtr, QTAtomID imageID, FixedPoint *registrationPoint, StringPtr imageName ) { OSErr err = noErr; Handle imageData; QTAtom defaultsAtom, imagesContainerAtom, imageAtom; ImageDescriptionHandle bigEndianImageDescription = nil; #if TARGET_RT_LITTLE_ENDIAN bigEndianImageDescription = (ImageDescriptionHandle) NewHandle(GetHandleSize((Handle)idh)); BlockMoveData( *idh, *bigEndianImageDescription, GetHandleSize((Handle)idh)); EndianUtils_ImageDescription_NtoB(bigEndianImageDescription); #else bigEndianImageDescription = idh; // already is big endian #endif // append compressed picture data to imageDescription to obtain sprite image data FailMemErr( imageData = NewHandle(0) ); FailMemErr( HandAndHand( (Handle)bigEndianImageDescription, imageData ) ); // imageData <= imageData + bigEndianImageDescription FailMemErr( PtrAndHand( compressedDataPtr, imageData, dataSize ) ); if ( (defaultsAtom = QTFindChildByIndex( keySample, 0, kSpriteSharedDataAtomType, 1, nil )) == 0 ) FailOSErr( QTInsertChild( keySample, 0, kSpriteSharedDataAtomType, 1, 0, 0, nil, &defaultsAtom ) ); if ( (imagesContainerAtom = QTFindChildByIndex( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, nil )) == 0 ) FailOSErr( QTInsertChild( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, 0, 0, nil, &imagesContainerAtom ) ); FailOSErr( QTInsertChild( keySample, imagesContainerAtom, kSpriteImageAtomType, imageID, 0, 0, nil, &imageAtom ) ); HLock( imageData ); FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageDataAtomType, 1, 0, GetHandleSize(imageData), *imageData, nil ) ); HUnlock( imageData ); if ( registrationPoint ) { FixedPoint tempRegistrationPoint; tempRegistrationPoint.x = EndianS32_NtoB(registrationPoint->x); tempRegistrationPoint.y = EndianS32_NtoB(registrationPoint->y); FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageRegistrationAtomType, 1, 0, sizeof(tempRegistrationPoint), &tempRegistrationPoint, nil ) ); } else { FixedPoint regPoint = { 0, 0 }; // Flipping {0,0} doesn't change anything so we don't flip FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageRegistrationAtomType, 1, 0, sizeof(regPoint), ®Point, nil ) ); } if( imageName ) { FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageNameAtomType, 1, 0, imageName[0], &imageName[1], nil ) ); } bail: #if TARGET_RT_LITTLE_ENDIAN if(bigEndianImageDescription) DisposeHandle((Handle)bigEndianImageDescription); #else // bigEndianImageDescription is still idh, so don't dispose of it #endif if ( imageData ) DisposeHandle( imageData ); return err; } OSErr AssignImageGroupIDsToKeyFrame( QTAtomContainer keySample ) { OSErr err = noErr; QTAtom defaultsAtom, imagesContainerAtom; ImageDescriptionHandle firstImageDesc = nil, secondImageDesc = nil; short firstIndex, secondIndex, numImages; CodecType firstImageType, secondImageType; long groupID = 0, testID; defaultsAtom = QTFindChildByIndex( keySample, 0, kSpriteSharedDataAtomType, 1, nil ); if ( ! defaultsAtom ) goto bail; imagesContainerAtom = QTFindChildByIndex( keySample, defaultsAtom, kSpriteImagesContainerAtomType, 1, nil ); if ( ! imagesContainerAtom ) goto bail; firstImageDesc = (ImageDescriptionHandle)NewHandle(0); if ( firstImageDesc == nil ) { err = memFullErr; goto bail; } secondImageDesc = (ImageDescriptionHandle)NewHandle(0); if ( secondImageDesc == nil ) { err = memFullErr; goto bail; } numImages = QTCountChildrenOfType( keySample, imagesContainerAtom, kSpriteImageAtomType ); for ( firstIndex = 1; firstIndex <= numImages; firstIndex++ ) { FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, firstIndex, 0 ) ); } for ( firstIndex = 1; firstIndex <= (numImages - 1); firstIndex++ ) { FailOSErr( GetImageGroupID( keySample, imagesContainerAtom, firstIndex, &testID ) ); if ( testID == 0 ) { groupID++; FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, firstIndex, groupID ) ); FailOSErr( GetImageDescription( keySample, imagesContainerAtom, firstIndex, firstImageDesc ) ); firstImageType = (**firstImageDesc).cType; for ( secondIndex = (firstIndex + 1); secondIndex <= numImages; secondIndex++ ) { FailOSErr( GetImageGroupID( keySample, imagesContainerAtom, secondIndex, &testID ) ); if ( testID == 0 ) { FailOSErr( GetImageDescription( keySample, imagesContainerAtom, secondIndex, secondImageDesc ) ); secondImageType = (**secondImageDesc).cType; if ( firstImageType == secondImageType ) { ImageSequence seqID; Boolean equivalent; FailOSErr( DecompressSequenceBegin( &seqID, firstImageDesc, nil, nil, nil, nil, ditherCopy, (RgnHandle)nil, 0, codecNormalQuality, anyCodec ) ); CDSequenceEquivalentImageDescription( seqID, secondImageDesc, &equivalent ); CDSequenceEnd( seqID ); if ( equivalent ) { FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, secondIndex, groupID ) ); } } } } } } // assign an ID to the last image FailOSErr( GetImageGroupID( keySample, imagesContainerAtom, numImages, &testID ) ); if ( testID == 0 ) { groupID++; FailOSErr( SetImageGroupID( keySample, imagesContainerAtom, numImages, groupID ) ); } bail: if ( firstImageDesc ) DisposeHandle( (Handle)firstImageDesc ); if ( secondImageDesc ) DisposeHandle( (Handle)secondImageDesc ); return err; } // •••• ImageDescriptionHandles are in native endianism, right? If so, we need to endian flip them before // they're returned from GetImageDescription. OSErr GetImageDescription( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, ImageDescriptionHandle imageDesc ) { OSErr err = noErr; QTAtom imageAtom, imageDataAtom; UInt8 saveState; UInt32 imageDescriptionSize; imageAtom = QTFindChildByIndex( keySample, imagesContainerAtom, kSpriteImageAtomType, imageIndex, nil ); if ( imageAtom == 0 ) { err = cannotFindAtomErr; goto bail; } imageDataAtom = QTFindChildByIndex( keySample, imageAtom, kSpriteImageDataAtomType, 1, nil ); if ( imageDataAtom == 0 ) { err = cannotFindAtomErr; goto bail; } saveState = HGetState( (Handle)imageDesc ); HUnlock( (Handle)imageDesc ); // Copy the data (ImageDescription followed by image data) to a handle FailOSErr( QTCopyAtomDataToHandle( keySample, imageDataAtom, (Handle)imageDesc ) ); imageDescriptionSize = EndianU32_BtoN((**imageDesc).idSize); // Pull off anything following the image description (& its color table, if any, and // any image description extensions. SetHandleSize( (Handle)imageDesc, imageDescriptionSize ); #if TARGET_RT_LITTLE_ENDIAN EndianUtils_ImageDescription_BtoN( imageDesc ); #endif HSetState( (Handle)imageDesc, saveState ); err = MemError(); bail: return err; } OSErr SetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long groupID ) { OSErr err = noErr; QTAtom imageAtom, imageGroupAtom; imageAtom = QTFindChildByIndex( keySample, imagesContainerAtom, kSpriteImageAtomType, imageIndex, nil ); if ( imageAtom == 0 ) { err = cannotFindAtomErr; goto bail; } imageGroupAtom = QTFindChildByIndex( keySample, imageAtom, kSpriteImageGroupIDAtomType, 1, nil ); if ( imageGroupAtom == 0 ) { FailOSErr( QTInsertChild( keySample, imageAtom, kSpriteImageGroupIDAtomType, 1, 1, 0, nil, &imageGroupAtom ) ); } groupID = EndianU32_NtoB(groupID); FailOSErr( QTSetAtomData( keySample, imageGroupAtom, sizeof( groupID ), &groupID ) ); bail: return err; } OSErr GetImageGroupID( QTAtomContainer keySample, QTAtom imagesContainerAtom, short imageIndex, long *groupID ) { OSErr err = noErr; QTAtom imageAtom, imageGroupAtom; imageAtom = QTFindChildByIndex( keySample, imagesContainerAtom, kSpriteImageAtomType, imageIndex, nil ); if ( imageAtom == 0 ) { err = cannotFindAtomErr; goto bail; } imageGroupAtom = QTFindChildByIndex( keySample, imageAtom, kSpriteImageGroupIDAtomType, 1, nil ); if ( ! imageGroupAtom ) *groupID = 0; else { FailOSErr( QTCopyAtomDataToPtr( keySample, imageGroupAtom, false, sizeof(*groupID), (Ptr)groupID, nil ) ); *groupID = EndianU32_BtoN(*groupID); // return native endian long } bail: return err; }